// 条款34：区分接口继承和实现继承
// 继承的两个方面
// 在C++中，继承可以分为两个不同但相关的方面：
// 1.接口继承：继承函数声明（函数的签名）
// 2.实现继承：继承函数的实际代码（函数体）

// 接口继承
// 接口继承是指派生类继承基类函数的声明，但不一定继承其实现。这表明派生类承诺支持基类定义的功能，但可以自由决定如何实现这些功能。
// 特点：
//      定义了"做什么"，而不是"怎么做"
//      建立了类型之间的关系（IS-A关系）
//      通常通过纯虚函数实现

class Shape
{
public:
    virtual double area() const = 0; // 纯虚函数，只定义接口
};

class Circle : public Shape
{
public:
    virtual double area() const override
    { // 必须提供实现
        return PI * radius_ * radius_;
    }

private:
    double radius_;
};

// 实现继承
// 实现继承是指派生类继承基类函数的实际代码实现。这让派生类可以复用基类的代码，而不必重新编写相同的功能。
// 特点：
//      定义了"怎么做"
//      提供了代码复用机制
//      通常通过非虚函数或带有默认实现的虚函数实现
class Vehicle
{
public:
    void startEngine()
    { // 非虚函数，所有派生类继承此实现
        engageStarter();
        if (engineRunning())
            return;
        injectFuel();
        fireIgnition();
    }

protected:
    virtual void engageStarter() = 0;
    virtual bool engineRunning() = 0;
    virtual void injectFuel() = 0;
    virtual void fireIgnition() = 0;
};

// 混合继承
// 在实际中，大多数继承关系都同时包含接口继承和实现继承。C++提供了几种机制来控制这种混合：
// 1.纯虚函数（pure virtual function）：
//      只提供接口继承，没有实现继承
//      派生类必须提供实现
//      使基类成为抽象类
// 2.普通虚函数（impure virtual function）：
//      提供接口继承和默认实现继承
//      派生类可以选择重写或使用默认实现
//      可能导致意外的行为
// 3.非虚函数（non-virtual function）：
//      提供强制的实现继承
//      派生类不能改变行为
//      表示所有派生类共享的不变行为

// 区分继承类型的设计策略
// 1. 纯接口继承（只继承接口）
// 使用纯虚函数，强制派生类提供自己的实现：
class Animal
{
public:
    virtual void makeSound() const = 0; // 纯虚函数
};

// 2. 接口继承+默认实现
// 使用带有实现的纯虚函数，提供默认实现但仍强制派生类显式选择：
class Animal
{
public:
    virtual void makeSound() const = 0; // 纯虚函数
protected:
    void defaultSound() const
    { // 默认实现
        std::cout << "Generic animal sound" << std::endl;
    }
};

class Dog : public Animal
{
public:
    virtual void makeSound() const override
    {
        defaultSound(); // 显式选择使用默认实现
    }
};

// 3. 接口继承+可选覆盖的默认实现
// 使用普通虚函数，提供默认实现，派生类可以选择覆盖：
class Animal
{
public:
    virtual void sleep() const
    { // 普通虚函数
        std::cout << "Zzz..." << std::endl;
    }
};

class Cat : public Animal
{
    // 可以选择覆盖sleep()，也可以直接继承实现
};

// 4. 强制实现继承
// 使用非虚函数，强制所有派生类使用相同实现：
class Animal
{
public:
    void breathe()
    { // 非虚函数
      // 所有动物都以相同方式呼吸
    }
};

// 接口继承与实现继承的本质
// 1.接口继承
//      本质：提供一个统一的对外接口，允许不同派生类有不同的实现
//      目的：确保类型兼容性和多态行为
//      关注点："做什么"（what to do）
//      体现：通过虚函数机制，特别是纯虚函数
// 2.实现继承
//      本质：提供一个统一的实现方式，让派生类复用代码
//      目的：代码复用，减少重复编写
//      关注点："怎么做"（how to do）
//      体现：通过非虚函数或带默认实现的虚函数

// 实际应用示例
// 接口继承示例：数据库连接
class DatabaseConnection
{
public:
    virtual void connect(const std::string &connectionString) = 0;
    virtual void executeQuery(const std::string &query) = 0;
    virtual void disconnect() = 0;
    virtual ~DatabaseConnection() {}
};

class MySQLConnection : public DatabaseConnection
{
public:
    void connect(const std::string &connectionString) override
    {
        // MySQL特有的连接实现
    }

    void executeQuery(const std::string &query) override
    {
        // MySQL特有的查询实现
    }

    void disconnect() override
    {
        // MySQL特有的断开连接实现
    }
};

class PostgreSQLConnection : public DatabaseConnection
{
    // PostgreSQL的不同实现...
};

// 实现继承示例：UI控件基类
class UIControl
{
public:
    // 所有控件共享的实现
    void setVisible(bool visible)
    {
        isVisible = visible;
        if (visible)
            onShow();
        else
            onHide();
    }

    void setPosition(int x, int y)
    {
        this->x = x;
        this->y = y;
        onPositionChanged();
    }

protected:
    // 可定制的钩子方法
    virtual void onShow() {}
    virtual void onHide() {}
    virtual void onPositionChanged() {}

private:
    bool isVisible;
    int x, y;
};

class Button : public UIControl
{
protected:
    void onShow() override
    {
        // 按钮特有的显示逻辑
    }
};

// 在实际设计中的应用策略
// 1. 模板方法模式
// 结合接口继承和实现继承的典型应用是模板方法模式：
class Algorithm
{
public:
    // 模板方法，提供算法骨架（实现继承）
    void execute()
    {
        initialize();
        step1();
        step2();
        cleanup();
    }

protected:
    // 共享实现
    void initialize()
    {
        // 通用初始化代码
    }

    // 接口继承部分
    virtual void step1() = 0;
    virtual void step2() = 0;

    // 共享实现
    void cleanup()
    {
        // 通用清理代码
    }
};

// 2. 策略模式
// 纯接口继承的典型应用是策略模式：
class SortStrategy
{
public:
    virtual void sort(std::vector<int> &data) = 0;
    virtual ~SortStrategy() {}
};

class QuickSort : public SortStrategy
{
public:
    void sort(std::vector<int> &data) override
    {
        // 快速排序实现
    }
};

class MergeSort : public SortStrategy
{
public:
    void sort(std::vector<int> &data) override
    {
        // 归并排序实现
    }
};

// 设计建议
// 根据C++参数传递的最佳实践和继承设计原则：
// 1.明确分离接口和实现：
//      使用纯虚函数明确定义接口
//      使用非虚函数或受保护的辅助函数提供实现
// 2.避免过度继承：
//      接口继承应该反映真正的"是一个"关系
//      实现继承应该考虑使用组合作为替代
// 3.参数传递考虑：
//      在接口方法中，对于不需修改的大型对象，使用const引用传递
//      对于小型内置类型，使用传值
// 4.考虑SOLID原则：
//      单一职责原则：每个类只负责一个功能
//      开闭原则：通过接口继承扩展功能，而不修改现有代码
//      里氏替换原则：派生类应该能替换其基类使用
//      通过清晰区分接口继承和实现继承，可以创建更灵活、更易维护的代码结构，同时避免继承带来的常见问题。